home *** CD-ROM | disk | FTP | other *** search
- // BEGIN FLOCK GPL
- //
- // Copyright Flock Inc. 2005-2007
- // http://flock.com
- //
- // This file may be used under the terms of of the
- // GNU General Public License Version 2 or later (the "GPL"),
- // http://www.gnu.org/licenses/gpl.html
- //
- // Software distributed under the License is distributed on an "AS IS" basis,
- // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- // for the specific language governing rights and limitations under the
- // License.
- //
- // END FLOCK GPL
- //
-
- const CC = Components.classes;
- const CI = Components.interfaces;
- const CR = Components.results;
- const CU = Components.utils;
-
-
- function DEBUG(X) { }
- //function DEBUG(X) { debug ('flockXmlRpc.js: '+X+'\n'); }
-
- CU.import("resource:///modules/FlockXPCOMUtils.jsm");
- CU.import("resource:///modules/ISO8601DateUtils.jsm");
-
- const FLOCK_XMLRPC_CLASS_NAME = "Flock XML-RPC";
- const FLOCK_XMLRPC_CLASS_ID =
- Components.ID("{709f57f4-a4e4-41bb-a38d-86309fbc4858}");
- const FLOCK_XMLRPC_CONTRACT_ID = "@flock.com/xmlrpc/server;1";
-
- const Base64 = {
- chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
- encode: function (aInput) {
- var output = '';
- while (aInput.length > 0) {
- output += Base64.chars[aInput.charCodeAt(0) >> 2];
- output += Base64.chars[((aInput.charCodeAt(0)&0x03) << 4) |
- (aInput.length>1?((aInput.charCodeAt(1)&0xF0) >> 4):0)];
- output += Base64.chars[aInput.length>1?
- ((aInput.charCodeAt(1)&0x0F)<<2) |
- (aInput.length>2?((aInput.charCodeAt(2)&0xC0) >> 6):0):64];
- output += Base64.chars[aInput.length>2?
- (aInput.charCodeAt(2)&0x3F):64];
- if (aInput.length > 3) {
- aInput = aInput.substr (3);
- } else {
- break;
- }
- }
- return output;
- },
- decode: function (aInput) {
- const regexp = new RegExp ('[^'+Base64.chars+']', 'g');
- var output = '';
-
- aInput = aInput.replace (regexp, '');
-
- // FIXME: aInput MUST now be a multiple of four characters long
-
- function sixbits (i) {
- if (i == '=') return 0;
- return Base64.chars.indexOf (i);
- }
-
- while (aInput.length >= 4) {
- output += String.fromCharCode ((sixbits (aInput[0]) << 2) |
- (sixbits (aInput[1]) >> 4));
- if (aInput[2] == '=') {
- break;
- }
- output += String.fromCharCode ((sixbits (aInput[1]) << 4) |
- (sixbits (aInput[2]) >>2));
- if (aInput[3] == '=') {
- break;
- }
- output += String.fromCharCode (((sixbits (aInput[2]) << 6) & 0xC0) |
- sixbits (aInput[3]));
- aInput = aInput.substr (4);
- }
- return output;
- }
- }
-
-
- var XmlRpcXml = {
- build: function XRX_build(value) {
- if (value == undefined) {
- return null;
- }
-
- // FIXME: do the next two blocks have the desired effect?
- if (value.QueryInterface) {
- value = value.QueryInterface(flockIXmlRpcValue);
- if (value == null) {
- return null;
- }
- } else {
- return null;
- }
- try {
- value = value.QueryInterface(flockIXmlRpcValue);
- } catch (e) {
- return value.toString();
- }
-
- switch (value.XmlRpcType) {
- case flockIXmlRpcValue.TYPE_INT:
- return <int>{ String(value.IntValue) }</int>;
- case flockIXmlRpcValue.TYPE_BOOLEAN:
- return <boolean>{ value.BooleanValue ? 1 : 0 }</boolean>;
- case flockIXmlRpcValue.TYPE_STRING:
- return <string>{ value.StringValue }</string>;
- case flockIXmlRpcValue.TYPE_DOUBLE:
- return <double>{ String(value.DoubleValue) }</double>;
- case flockIXmlRpcValue.TYPE_DATETIME:
- var date = new Date();
- date.setTime(value.DateTimeValue * 1000);
- var datetime = ISO8601DateUtils.create(date);
- return <dateTime.iso8601>{datetime}</dateTime.iso8601>;
- case flockIXmlRpcValue.TYPE_ARRAY:
- var elements = value.ArrayElements({});
- var array = <array><data/></array>;
- for (var i = 0; i < elements.length; i++) {
- var q = XmlRpcXml.build(elements[i]);
- if (q == null) {
- continue;
- }
- array.data.foo = <value>{q}</value>;
- }
- return array;
- case flockIXmlRpcValue.TYPE_STRUCT:
- var keys = value.StructKeys({});
- var struct = <struct/>;
- for (var i in keys) {
- var q = XmlRpcXml.build(value.StructItem(keys[i]));
- if (q == null) {
- continue;
- }
- struct.foo = <member>
- <name>{keys[i]}</name>
- <value>{q}</value>
- </member>;
- }
- return struct;
- case flockIXmlRpcValue.TYPE_BASE64:
- return <base64>{ Base64.encode(value.Base64Value) }</base64>;
- default:
- throw "error building XML";
- return null;
- }
- },
- parse: function XRX_parse(xml) {
- DEBUG("XmlRpcXml.parse:" + xml);
- if (xml == undefined) {
- // this is the empty string
- return "";
- }
- if (xml.nodeKind() == "text") {
- // the default type in string
- return XmlRpcValue.String(xml.toString());
- }
- switch (xml.name().toString()) {
- case "int":
- case "i4":
- return XmlRpcValue.Int(parseInt(xml.text()));
- case "boolean":
- return XmlRpcValue.Boolean(parseInt(xml.text()) == 1);
- case "string":
- return XmlRpcValue.String (xml.text().toString());
- case "double":
- return XmlRpcValue.Double(parseFloat (xml.text()));
- case "dateTime.iso8601":
- var val = xml.text().toString();
- var myDate = ISO8601DateUtils.parse(val);
- return XmlRpcValue.DateTime(myDate);
- case "array":
- var arr = [];
- for (var i = 0; i < xml.data.value.length(); i++) {
- arr.push(XmlRpcXml.parse(xml.data.value[i].children()[0]));
- }
- return XmlRpcValue.Array(arr);
- case "struct":
- var struct = {};
- for (var i = 0; i < xml.member.length(); i++) {
- struct[xml.member[i].name.text()] =
- XmlRpcXml.parse(xml.member[i].value.children()[0]);
- }
- return XmlRpcValue.Struct(struct);
- case "base64":
- return XmlRpcValue.Base64(Base64.decode(xml.text().toString()));
- default:
- throw "error parsing XML";
- }
- }
- }
-
-
-
- // flockXmlRpcServer object
- function flockXmlRpcServerComponent() {
- this.mURL = null;
- this.mTimeout = null;
- }
-
- flockXmlRpcServerComponent.prototype = new FlockXPCOMUtils.genericComponent(
- FLOCK_XMLRPC_CLASS_NAME,
- FLOCK_XMLRPC_CLASS_ID,
- FLOCK_XMLRPC_CONTRACT_ID,
- flockXmlRpcServerComponent,
- 0, // nsIClassInfo flags
- [CI.flockIXmlRpcServer]
- );
-
- flockXmlRpcServerComponent.prototype.init =
- function XRSC_init(aURL) {
- DEBUG('flockXmlRpcServer.init("' + aURL + '")');
- this.mURL = aURL;
- this.mTimeout = 120 * 1000;
- }
-
- flockXmlRpcServerComponent.prototype.call =
- function XRSC_call(aMethod, aArguments, aListener) {
- // var aOptionalTimeoutInSeconds = 10;
- DEBUG("flockXmlRpcServer.call("
- + aMethod + ", "
- + aArguments + ", "
- + aListener + ")\n");
-
- if (aArguments.XmlRpcType != flockIXmlRpcValue.TYPE_ARRAY) {
- aListener.onError("the arguments must be in an xmrpc array");
- return;
- }
-
- var methodCall = <methodCall/>;
- methodCall.methodName = aMethod;
-
- var arguments = aArguments.ArrayElements({});
- DEBUG("XMLRPC: got " + arguments.length + " arguments");
- for (var i in arguments) {
- DEBUG("XMLRPC: adding arg " + XmlRpcXml.build(arguments[i]));
- methodCall.params.param +=
- <param>
- <value>{ XmlRpcXml.build(arguments[i]) }</value>
- </param>;
- }
-
- var url = this.mURL;
- var timeout = this.mTimeout;
- var callback = {};
- callback.notify = function XRSC_call_callback_notify(timer) {
- var xhr = CC["@mozilla.org/xmlextras/xmlhttprequest;1"]
- .createInstance(CI.nsIXMLHttpRequest);
- xhr.open("POST", url, true);
- xhr.setRequestHeader("Content-Type", "text/xml");
-
- // FIXME: what about charsets?
- // FIXME: should we make this configurable?
- xhr.overrideMimeType("text/xml");
-
- xhr.onreadystatechange = function XRSC_call_xhr(aEvent) {
- if (xhr.readyState == 4) {
- if (!xhr.responseXML) {
- aListener.onError (xhr.responseText);
- return;
- }
-
- if (xhr.status != 200) {
- aListener.onError (xhr.statusText);
- return;
- }
-
- //save the state of the XML object directives
- Orig_XML_ignoreComments = XML.ignoreComments;
- Orig_XML_ignoreProcessingInstructions = XML.ignoreProcessingInstructions;
- Orig_XML_ignoreWhitespace = XML.ignoreWhitespace;
- Orig_XML_prettyPrinting = XML.prettyPrinting;
- Orig_XML_prettyIndent = XML.prettyIndent;
- //set them to what we need for the parser to behave
- XML.ignoreComments = true;
- XML.ignoreProcessingInstructions = true;
- XML.ignoreWhitespace = true;
- XML.prettyPrinting = false;
- XML.prettyIndent = false;
-
- //var response = new XML(xhr.responseXML);
- var serializer = CC["@mozilla.org/xmlextras/xmlserializer;1"]
- .createInstance(CI.nsIDOMSerializer);
- var xmlStr =
- serializer.serializeToString(xhr.responseXML.documentElement);
-
- var response = new XML(xmlStr);
-
- if (response.name() != "methodResponse" ||
- !(response.params.param.value.length() == 1 ||
- response.fault.value.struct.length() == 1))
- {
- aListener.onError("invalid response XML: " + xhr.responseText);
- return;
- }
-
- if (response.params.param.value.length() == 1) {
- var resp = XmlRpcXml.parse(response.params.param.value.children()[0]);
- aListener.onResult(resp);
- //put them back like we found them before we return
- XML.ignoreComments = Orig_XML_ignoreComments;
- XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
- XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
- XML.prettyPrinting = Orig_XML_prettyPrinting;
- XML.prettyIndent = Orig_XML_prettyIndent;
- return;
- }
-
- var fault =
- XmlRpcValue.ToJavaScript(XmlRpcXml.parse(response.fault.value.struct));
- if (fault["faultCode"] == undefined ||
- fault["faultString"] == undefined)
- {
- aListener.onError("invalid response XML: " + xhr.responseText);
- //put them back like we found them before we return
- XML.ignoreComments = Orig_XML_ignoreComments;
- XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
- XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
- XML.prettyPrinting = Orig_XML_prettyPrinting;
- XML.prettyIndent = Orig_XML_prettyIndent;
- return;
- }
-
- aListener.onFault(fault["faultCode"], fault["faultString"]);
- //put them back like we found them before we return
- XML.ignoreComments = Orig_XML_ignoreComments;
- XML.ignoreProcessingInstructions = Orig_XML_ignoreProcessingInstructions;
- XML.ignoreWhitespace = Orig_XML_ignoreWhitespace;
- XML.prettyPrinting = Orig_XML_prettyPrinting;
- XML.prettyIndent = Orig_XML_prettyIndent;
- return;
- }
- }
-
- DEBUG('XMLRPC: sending: '
- + '<?xml version="1.0"?>\n'
- + methodCall.toXMLString());
- DEBUG('XMLRPC timeout is "' + timeout + '"');
-
- var timeoutCallback= {};
- timeoutCallback.notify = function XRSC_call_timeout_notify(timer) {
- DEBUG("timeoutCallback.notify called");
- if (xhr == null) {
- DEBUG("flockXmlRpcServerComponent.prototype.call.timeoutCallback "
- + "called with null request!!");
- } else if ((xhr != null) && (xhr.readyState != 4)) {
- DEBUG("XMLRPC timed out");
- //the request still exists and hasn't completed
- delete xhr["onreadystatechange"]; //Kill the callback function
- xhr.abort(); //abort the request
- aListener.onError("timeout"); //return an error to the caller
- }
- }
-
- var timeOutTimer = CC["@mozilla.org/timer;1"]
- .createInstance(CI.nsITimer);
- timeOutTimer.initWithCallback(timeoutCallback, timeout,
- CI.nsITimer.TYPE_ONE_SHOT);
-
- xhr.send('<?xml version="1.0"?>\n' + methodCall.toXMLString());
- }
-
- var timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
- timer.initWithCallback(callback, 1, CI.nsITimer.TYPE_ONE_SHOT);
- }
-
-
- // load the XMLRPC helper
- var loader = CC['@mozilla.org/moz/jssubscript-loader;1']
- .getService(CI.mozIJSSubScriptLoader);
- loader.loadSubScript("chrome://flock/content/xmlrpc/xmlrpchelper.js");
-
- var NSGetModule =
- FlockXPCOMUtils.generateNSGetModule(FLOCK_XMLRPC_CLASS_NAME,
- [flockXmlRpcServerComponent]);
-